
// soule // HEURISTIQUE
// Il va nous servir pour choisir quel emplacement joue a noeud n(i)
// On va se base sur un vecteur qui garde tous les mouvements possible, classé avec leur meilleur ratio
// de victoires / nombres de fois joues

#include "listeChaineeUTC.h"
#include "arbreUTCtrace.h"
ofstream fichier2("addMtrick.txt", ios::ate | ios::out);
// CONSTRUCTEURS
// cree la liste vide
listeChaineeUTC::listeChaineeUTC()
{
    racine = NULL;
    nbMaillon = 0;
}
//constructeur par copie
listeChaineeUTC::listeChaineeUTC(listeChaineeUTC * l)
{
    if (l->racine== NULL)
    {
        racine = NULL;
        nbMaillon = 0 ;
    }
    else
    {
        nbMaillon=l->nbMaillon;
        maillonUTC * monMaillon = (struct maillonUTC *) malloc(sizeof(maillonUTC));
        (*monMaillon) = (* l->racine);
        racine = monMaillon;

        for (maillonUTC* maillonCourant = l->racine->suivant; maillonCourant != NULL; maillonCourant = maillonCourant->suivant)
        {
            monMaillon->suivant = (maillonUTC *) malloc(sizeof(maillonUTC));
            monMaillon = monMaillon->suivant;
            (*monMaillon) = (* maillonCourant); //truc horrible
        }

    }
}



// ACCESSEURS
maillonUTC * listeChaineeUTC::getRacine()
{
    return this->racine ;
}

int listeChaineeUTC::getNbMaillon()
{
    return this->nbMaillon ;
}

maillonUTC *listeChaineeUTC::existe(maillonUTC *m)
{
        maillonUTC *maillonCourant=racine;
        while(maillonCourant != NULL)
        {
                if(maillonCourant->coup.x == m->coup.x && maillonCourant->coup.y == m->coup.y && maillonCourant->coup.c == m->coup.c)
                {
                        return maillonCourant;
                }
                maillonCourant=maillonCourant->suivant;
        }
        return NULL;
}

// METHODES
// ajoute un maillon dans la liste pour la garder dans l'ordre decroissant le ratio des Coup
void listeChaineeUTC::ajouterMaillon(maillonUTC* m)
{
    //cerr<<endl<< "    debut ajout maillon" <<endl ;

    //afficherListeMaillons() ;

    //cerr <<"  On va ajouter le maillon :"<< m->coup.x << "," << m->coup.y << "," << m->coup.c << ";" << m->score << "," << m->nbJeux << endl;
    maillonUTC* maillonCourant, *maillonPrecedent ;
    maillonCourant = racine ;
    maillonPrecedent = racine ;
    float ratioCourant, ratioAjout ;
    int compteurMaillon = 0 ;


    // on parcoure la liste pour trouver le premier ratio inferieur au ratio du maillon
    // qu'on veut ajouter
    cerr<<"    avant le if"<<endl ;
    if (maillonCourant == NULL)
    {
        // si pas de maillons on l'initialise
        cerr<<"    si pas de maillon"<<endl ;
        racine = m ;
        racine->suivant = NULL ;
    }
    else // si ya deja des maillons
    {
        cerr<<"    si ya deja des maillons"<<endl ;
        ratioCourant = (float)maillonCourant->score / (float)maillonCourant->nbJeux ;
        ratioAjout = (float)m->score / (float)m->nbJeux ;
        cerr<<"3"<<endl ;
        cerr<<"    on va comparer ratiocourant : "<<ratioCourant<<" avec ratioAjout : "<<ratioAjout<<endl ;
        while (ratioCourant > ratioAjout && maillonCourant != NULL)
        {
            cerr<<"1"<<endl ;
            maillonPrecedent = maillonCourant ;
            maillonCourant = maillonCourant->suivant ;
            compteurMaillon++ ;
            cerr<<"2"<<endl ;
            if (maillonCourant != NULL)
            {
                ratioCourant = (float)maillonCourant->nbVictoires / (float)maillonCourant->nbJeux ;
                ratioAjout = (float)m->nbVictoires / (float)m->nbJeux ;
                cerr<<"3"<<endl ;
                cerr<<"    on va comparer ratiocourant : "<<ratioCourant<<" avec ratioAjout : "<<ratioAjout<<endl ;
                cerr<<"4"<<endl ;
            }

        }
        if (maillonCourant == NULL) // si fin de la liste
        {
            //on ajoute a la toute fin
            cerr<<"    si fin de la liste"<<endl ;
            maillonPrecedent->suivant = m ;
            m->suivant=NULL ;
        }
        else // il faut brancher precedent avec m et m avec courant
        {
            // on gere le cas ou y'a que 2 maillons
            cerr<<"    on a compteurMaillon = "<<compteurMaillon<<endl ;
            if (compteurMaillon == 0)
            {
                cerr<<"    on va brancher le ratio dajout "<<ratioAjout<<" en tant que racine, et il pointera sur celui qui etait avant : "<<ratioCourant<<endl ;
                this->racine = m ;
            }
            else
            {
                cerr<<"    on va brancher le ratioPrecedent "<<(float)maillonPrecedent->nbVictoires / (float)maillonPrecedent->nbJeux<<" au ratioAjout "<<ratioAjout<<" et au ratioCourant "<<ratioCourant<<endl ;

                maillonPrecedent->suivant = m ;
            }
            m->suivant = maillonCourant ;
        }
    }
    cerr<<"        AVANT DE quitter"<<endl ;
    afficherListeMaillons() ;
    this->nbMaillon++ ;
}


  float listeChaineeUTC::getRatio(maillonUCT monMaillon){


		return (float)monMaillon->score / (float)monmaillon->nbJeux ;
  	}


// trouver le coup disponible avec le meilleur ratio. Renvoi -10 -10 si aucun ratio sup à 0.5
Coup listeChaineeUTC::trouverMeilleurMaillon()
{

    maillonUTC* maillonCourant  = racine ;
    //cout<<"pre while"<<endl;
    while (maillonCourant != NULL && (maillonCourant->lu == false  && maillonCourant->libre == false))
    {

        //cout<<maillonCourant<<endl;
        //cout<<" - "<<maillonCourant->suivant <<endl;
        maillonCourant = maillonCourant->suivant ;
        //cout<<"n w"<<endl;
    }
    if (maillonCourant != NULL && maillonCourant->getRatio() > 0.5)
    {
        maillonCourant->libre = true;
        return maillonCourant->coup ;
    }
    else   // soit la liste est vide, soit tous les coups ont deja ete joues
    {
        Coup temp ;
        temp.x = -10 ;
        temp.y = -10 ;
        temp.c = VIDE;
        return temp ;
    }
}


// trouver le coup disponible avec le meilleur ratio. TIENS COMPTE DES COUPS POSSIBLES SUR LE GOBAN ACTUEL. Renvoi -10 -10 si aucun ratio sup à 0.5
Coup listeChaineeUTC::trouverMeilleurMaillon( Goban * g)
{
    maillonUTC* maillonCourant  = racine ;
    //cout<<"pre while"<<endl;
    while (maillonCourant != NULL && (maillonCourant->libre == false || !g->caseJouable( maillonCourant->coup)))
    {

        maillonCourant = maillonCourant->suivant ;
    }
    if (maillonCourant != NULL && maillonCourant->getRatio() > 0.5 && g->caseJouable( maillonCourant->coup) )
    {
        return maillonCourant->coup ;
    }
    else   // soit la liste est vide, soit tous les coups ont deja ete joues
    {
        Coup temp ;
        temp.x = -10 ;
        temp.y = -10 ;
        temp.c = VIDE;
        return temp ;
    }
}

// renvoi le ratio correspondant au Coup donne. Renvoi -1 si le coup n'existe pas
float listeChaineeUTC::trouverRatio(Coup c)
{
    maillonUTC* maillonCourant = this->racine ;
    while (maillonCourant != NULL && maillonCourant->coup.x != c.x && maillonCourant->coup.y != c.y)
    {
        maillonCourant = maillonCourant->suivant ;
    }
    if (maillonCourant == NULL)   // si on est a la fin sans avoir trouver le coup
    {
        return 0 ;
    }
    else   // si on a trouvé le bon coup
    {
        float ratio = maillonCourant->getRatio();
        return ratio ;
    }
}


void listeChaineeUTC::majVraiMaillon(maillonUTC * maillonCherche,listeChaineeUTC * listeChainee)
{
    maillonUTC * maillonListe=listeChainee->racine; //le maillon de la VRAIE liste
//maillonUTC * maillonCourant = ;
    maillonUTC m1;
    maillonUTC m2;
    m1.nbJeux =1;
    m1.nbVictoires = 1000000;
    m1.suivant= &m2;

    m2.nbJeux =1;
    m2.nbVictoires =1000000;
    m2.suivant= maillonListe;

    maillonUTC* maillonPrePrecedent = &m1;

//parcours de la VRAIE liste par le préprécédent
    while (maillonPrePrecedent->suivant->suivant!=NULL  && (maillonPrePrecedent->suivant->suivant->coup.x!= maillonCherche->coup.x || maillonPrePrecedent->suivant->suivant->coup.y!=maillonCherche->coup.y))
    {
        maillonPrePrecedent=maillonPrePrecedent->suivant;
    }
    if  (maillonPrePrecedent->suivant->suivant!=NULL)
    {
        //on a trouvé le bon maillon
        maillonListe=maillonPrePrecedent->suivant->suivant;


        maillonListe->nbJeux+= maillonCherche->nbJeuxTemp ;
        maillonCherche->nbJeuxTemp =0;

        //maillonCourant->libre = true ;
        if (maillonCherche->nbVictoiresTemp>0)
        {
            //cout <<"Coup : "<<(int)maillonCourant->coup.x<<" - "<<(int)maillonCourant->coup.y<<" : "<<maillonCourant->coup.c<<" : "<<maillonCourant->nbJeux<<" / "<<maillonCourant->nbVictoires<<endl;
            //   cout<<"coup de winneur"<<endl;
            maillonListe->nbVictoires+= maillonCherche->nbVictoiresTemp;
            maillonCherche->nbVictoiresTemp =0;
            // cout<<maillonPrePrecedent<<" - "<<maillonPrePrecedent->suivant<<" - "<<maillonPrePrecedent->suivant->suivant<<" = "<<maillonCourant<<" - "<<maillonCourant->suivant<<endl;
            if (maillonListe->getRatio() > maillonPrePrecedent->suivant->getRatio() )
            {
                //  cout<<"switch : "<<(float)maillonCourant->nbVictoires / maillonCourant->nbJeux<<" vs "<<(float) maillonPrePrecedent->suivant->nbVictoires / maillonPrePrecedent->suivant->nbJeux<<endl;
                if (listeChainee->racine == maillonPrePrecedent->suivant)
                {
                    listeChainee->racine = maillonListe;
                }
                //SWITCH de cellules sur la VRAIE liste
                maillonPrePrecedent->suivant->suivant = maillonListe->suivant;
                maillonListe->suivant = maillonPrePrecedent->suivant;
                maillonPrePrecedent->suivant = maillonListe;
                maillonListe = maillonListe->suivant;
            }
            //cout<<maillonPrePrecedent<<" - "<<maillonPrePrecedent->suivant<<" - "<<maillonPrePrecedent->suivant->suivant<<" = "<<maillonCourant<<" - "<<maillonCourant->suivant<<" = "<<maillonPrePrecedent->suivant->suivant<<endl;
        }

    }
    else
    {
        cout<<"erreur dans majVraiMaillon, on a pas trouvé le maillon du coup donné : "<<(int)maillonCherche->coup.x <<" - "<<(int)maillonCherche->coup.y<<endl;
    }
}


// augmente de 1 le nombre de jeux et remet les coups a 'libre'
// augmente aussi les victoires si le boolean est a vrai
void listeChaineeUTC::partieFinie(listeChaineeUTC * listeChainee){
    maillonUTC* maillonCourant = this->racine; // le maillon courant de la liste CUSTOM
// Parcours de la liste CUSTOM
    while (maillonCourant != NULL)
    {
        //si le maillon courant de la liste custom a été utilisé
        if (maillonCourant->nbJeuxTemp > 0)
        {
            //on cherche le maillon original qui correspond:
            majVraiMaillon(maillonCourant, listeChainee);
        }
        maillonCourant = maillonCourant->suivant ;
    }
}

bool test(int n)
{
    cout<<"test : "<<n<<endl;
    return 1;
}
// On veut jouer ce coup. La fonction verifie que le coup n'existe pas
// deja Si  non, il est rajouter a la liste chainee



// augmente de 1 le nombre de jeux et remet les coups a 'libre'
// augmente aussi les victoires si le boolean est a vrai
void listeChaineeUTC::partieFinie(bool b) {

    maillonUTC* maillonCourant = this->racine ;
    maillonUTC* maillonTemp;
    maillonUTC m1;
    maillonUTC m2;
    m1.nbJeux =1;
    m1.nbVictoires = 1000000;
    m1.suivant= &m2;

    m2.nbJeux =1;
    m2.nbVictoires =1000000;
    m2.suivant= maillonCourant;

    maillonUTC* maillonPrePrecedent = &m1;

    while (maillonCourant != NULL) {
        maillonCourant->lu = false;
        /*cout<<"while de partie fini"<<endl;
        cout<<maillonCourant->coup.x<<" - "<<maillonCourant->coup.y<<endl;
        cout<<maillonPrePrecedent->coup.x<<" - "<<maillonPrePrecedent->coup.y<<endl; */
        if (maillonCourant->libre == false) {
        maillonCourant->nbJeuxTemp++ ;
        maillonCourant->nbJeux++ ;

            maillonCourant->libre = true ;
            if (b == true) {
                //cout <<"Coup : "<<(int)maillonCourant->coup.x<<" - "<<(int)maillonCourant->coup.y<<" : "<<maillonCourant->coup.c<<" : "<<maillonCourant->nbJeux<<" / "<<maillonCourant->nbVictoires<<endl;
             //   cout<<"coup de winneur"<<endl;
                maillonCourant->nbVictoiresTemp++ ;
                maillonCourant->nbVictoires++ ;
               // cout<<maillonPrePrecedent<<" - "<<maillonPrePrecedent->suivant<<" - "<<maillonPrePrecedent->suivant->suivant<<" = "<<maillonCourant<<" - "<<maillonCourant->suivant<<endl;
              /*  if((float)maillonCourant->nbVictoires / maillonCourant->nbJeux > ( (float) maillonPrePrecedent->suivant->nbVictoires / maillonPrePrecedent->suivant->nbJeux) ){
                  //  cout<<"switch : "<<(float)maillonCourant->nbVictoires / maillonCourant->nbJeux<<" vs "<<(float) maillonPrePrecedent->suivant->nbVictoires / maillonPrePrecedent->suivant->nbJeux<<endl;
                    if (racine == maillonPrePrecedent->suivant){
                        racine = maillonCourant;
                    }
                    maillonPrePrecedent->suivant->suivant = maillonCourant->suivant;
                    maillonCourant->suivant = maillonPrePrecedent->suivant;
                    maillonPrePrecedent->suivant = maillonCourant;
                    maillonCourant = maillonCourant->suivant;
                }
                //cout<<maillonPrePrecedent<<" - "<<maillonPrePrecedent->suivant<<" - "<<maillonPrePrecedent->suivant->suivant<<" = "<<maillonCourant<<" - "<<maillonCourant->suivant<<" = "<<maillonPrePrecedent->suivant->suivant<<endl;
            */
            }
        }
        //cout<<"preparation du prochain passage"<<endl;
        maillonCourant = maillonCourant->suivant ;
        maillonPrePrecedent = maillonPrePrecedent->suivant;
    }
    last = maillonPrePrecedent->suivant;
    //cout<<"last 1 : "<<last<<" - last 1 s : "<<last->suivant<<endl;
    //cout<<"last1 coup : "<<(int)last->coup.x<<" - "<<(int)last->coup.y<<" - "<<last->coup.c<<endl;
}



void listeChaineeUTC::veutJouer(Coup c)
{
    //cout<<"veutjouercoup : "<<(int)c.x<<" - "<<(int)c.y<<" : "<<c.c<<endl;
    //cout<<"vj"<<endl;
    maillonUTC* maillonCourant ;
    maillonCourant = racine ;
    //maillonUTC *maillonAvant = maillonCourant;
    //cout<<"pre boucle"<<endl;
    if (racine == NULL)
    {
        maillonUTC * m = (struct maillonUTC *) malloc(sizeof(maillonUTC));
        m->coup = c ;
        m->nbVictoires = 0 ;
        m->nbJeux = 0 ;
        m->nbVictoiresTemp = 0;
        m->nbJeuxTemp = 0;
        m->libre = false ;
        m->lu = false;
        m->suivant = NULL;
        racine = m;
    }
    else
    {
        while (maillonCourant->suivant != NULL && !(maillonCourant->coup.x == c.x && maillonCourant->coup.y == c.y))
        {
            //cout<<"while : "<<maillonCourant<<" - "<<maillonCourant->suivant <<endl;
            maillonCourant = maillonCourant->suivant ;
            // cout<<"while 2 : "<<maillonCourant<<endl;
        }
        // on a parcouru toute la liste, le coup n'existait pas, on l'ajoute

        if ( !(maillonCourant->coup.x == c.x && maillonCourant->coup.y == c.y))
        {
            //cout<<"if"<<endl;
            maillonUTC * m = (struct maillonUTC *) malloc(sizeof(maillonUTC));
            m->coup = c ;
            //cout<<" c v j : "<<(int)c.x<<" - "<<(int)c.y<<" : "<<c.c<<endl;
            m->nbVictoires = 0 ;
            m->nbJeux = 0 ;
            m->nbVictoiresTemp = 0 ;
            m->nbJeuxTemp = 0 ;
            m->libre = false ;
            m->lu = false;
            m->suivant = NULL;
            maillonCourant->suivant = m;
            //cout<<"fin if"<<endl;
        }
        else   // on a trouvé le coup en question
        {
            maillonCourant->libre =  false ;
        }
        //cout<<"fin vj"<<endl;
    }

}







void listeChaineeUTC::addMaillonTrick(Coup c, int x )
{
    fichier2<<(int)c.x<<" - "<<(int)c.y<<" : "<<x<<endl;
    maillonUTC* maillonTemp;
    maillonUTC m1;
    maillonUTC m2;
    m1.nbJeux =1;
    m1.score = 1000000;
    m1.suivant= &m2;

    m2.nbJeux =1;
    m2.score =1000000;
    m2.suivant= racine;


    maillonUTC* maillonCourant = &m1;

    while (maillonCourant->suivant->suivant != NULL && (maillonCourant->suivant->suivant->coup.x != c.x || maillonCourant->suivant->suivant->coup.y != c.y ))
    {
        maillonCourant = maillonCourant->suivant;
    }

    if (maillonCourant->suivant->suivant != NULL) // Le maillon existe deja.
    {
        fichier2<<" avant :  "<<(int)maillonCourant->suivant->suivant->coup.x<<" - "<<(int)maillonCourant->suivant->suivant->coup.y<<" : "<<maillonCourant->suivant->suivant->score<<" / "<<maillonCourant->suivant->suivant->nbJeux<<endl;
        maillonCourant->suivant->suivant->nbJeux += abs(x/10); //remetre +=
        if (x>1)
        {
            maillonCourant->suivant->suivant->score += (abs(x/10) -2*sqrt(x/10 + 1) ); //remetre +=
        }

        fichier2<<" apres :  "<<(int)maillonCourant->suivant->suivant->coup.x<<" - "<<(int)maillonCourant->suivant->suivant->coup.y<<" : "<<maillonCourant->suivant->suivant->score<<" / "<<maillonCourant->suivant->suivant->nbJeux<<endl;
        while ( maillonCourant->suivant->getRatio() < maillonCourant->suivant->suivant->getRatio() ) //A REMPLACER PAR UN TRI FUSION A LA FIN DES AJOUTS
        {
            if (racine == maillonCourant->suivant)
            {
                racine = maillonCourant->suivant->suivant;
            }
            maillonTemp = maillonCourant->suivant->suivant;
            maillonCourant->suivant->suivant = maillonCourant->suivant->suivant->suivant;
            maillonTemp->suivant = maillonCourant->suivant;
            maillonCourant->suivant = maillonTemp;

            //on recule d'un pas ds la liste.
            maillonTemp = &m1;
            while (maillonTemp->suivant != maillonCourant)
            {
                maillonTemp = maillonTemp->suivant;
            }
            maillonCourant = maillonTemp;
        }

    }
    else   //Si le maillon n'existe aps dans la liste...
    {

        maillonCourant = &m2;


        while (maillonCourant->suivant !=NULL && (maillonCourant->suivant->score   > x))
        {
            maillonCourant = maillonCourant->suivant;
        }

        maillonUTC * m = (struct maillonUTC *) malloc(sizeof(maillonUTC));
        m->coup = c ;
        //cout<<" c v j : "<<(int)c.x<<" - "<<(int)c.y<<" : "<<c.c<<endl;
        m->nbJeux = abs(x)/4;
        if (x>0)
        {
            m->score = (abs(x) -sqrt(x) +0.5*abs(x))/4;
        } else {
            m->score = 1;
        }

        m->libre = true ;
        m->lu = false;
        m->suivant = maillonCourant->suivant;
        m->nbJeuxTemp=0;
        m->scoreTemp=0;
        maillonCourant->suivant = m;



        if (maillonCourant == &m2)
        {
            racine = m;
        }
    }
}

void listeChaineeUTC::raz()
{
    if (racine != NULL)
    {
        delMaillon(racine);
        racine = NULL;
    }
}

void listeChaineeUTC::delMaillon( maillonUTC * m )
{
    if (m->suivant != NULL)
        delMaillon(m->suivant);
    delete m;
}



void listeChaineeUTC::divise(int n)
{
    for (maillonUTC* maillonCourant = racine; maillonCourant != NULL; maillonCourant = maillonCourant->suivant)
    {
        maillonCourant->nbJeux = (maillonCourant->nbJeux / (n+1)) + 2*n;
        maillonCourant->score = (maillonCourant->score / (n+1) )+ 1*n;  // /!\ a changer !?
    }
}


void listeChaineeUTC::afficherListeMaillons()
{
    cout<<" -> Affichage de la liste des maillons : "<<endl ;
    maillonUTC *maillon = racine;
    while (maillon != NULL)
    {
        cout<<"["<<maillon->getRatio()<<"] "<<(int) maillon->coup.x << "," <<(int) maillon->coup.y << "," << maillon->coup.c << ";" << maillon->score << "," << maillon->nbJeux ;
        maillon=maillon->suivant;
        if (maillon != NULL)
        {
            cout << " | ";
        }
    }
    cout<<endl ;
}
